package com.jwater.core.manager.common.conf;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jwater.core.common.param.ParamMap;
import com.jwater.core.common.param.ParamMapImpl;
import com.jwater.core.common.xml.XmlConfig;
import com.jwater.core.manager.common.DataKeys;
import com.jwater.core.manager.common.model.JobInfo;
import com.jwater.launch.DeployPathUtils;
import com.jwater.launch.HomePath;

/**
 * @description:定时任务解析器
 * @author: jnner
 * @createDate: 2021/2/5
 * @version: 1.0
 */
public class JobConfParse {
    protected static Logger logger = LoggerFactory.getLogger(JobConfParse.class);
    protected Map<String, JobInfo> jobInfos = new ConcurrentHashMap<>();

    /**
     * 获取定时任务信息
     *
     * @return
     */
    public Map<String, JobInfo> getJobInfos() {
        return jobInfos;
    }

    /**
     * 获取定时任务信息
     *
     * @param regionName
     * @param deployName
     * @param groupName
     * @return
     */
    public List<JobInfo> getGroupJobInfo(String regionName, String deployName, String groupName) {
        List<JobInfo> list = new ArrayList<>();
        for (JobInfo jobInfo : jobInfos.values()) {
            if (regionName.equals(jobInfo.getRegionName()) && deployName.equals(jobInfo.getDeployName())
                    && groupName.equals(jobInfo.getGroupName())) {
                list.add(jobInfo);
            }
        }
        return list;
    }

    /**
     * 获取定时任务信息
     *
     * @param regionName
     * @return
     */
    public List<JobInfo> getRegionJobInfo(String regionName) {
        List<JobInfo> list = new ArrayList<>();
        for (JobInfo jobInfo : jobInfos.values()) {
            if (regionName.equals(jobInfo.getRegionName())) {
                list.add(jobInfo);
            }
        }
        return list;
    }

    /**
     * 获取定时任务信息
     *
     * @param regionName
     * @param deployName
     * @return
     */
    public List<JobInfo> getDeployJobInfo(String regionName, String deployName) {
        List<JobInfo> list = new ArrayList<>();
        for (JobInfo jobInfo : jobInfos.values()) {
            if (regionName.equals(jobInfo.getRegionName()) && deployName.equals(jobInfo.getDeployName())) {
                list.add(jobInfo);
            }
        }
        return list;
    }

    /**
     * 获取定时任务信息
     *
     * @param regionName
     * @param deployName
     * @param groupName
     * @param jobName
     * @return
     */
    public JobInfo getJobInfo(String regionName, String deployName, String groupName, String jobName) {
        for (JobInfo jobInfo : jobInfos.values()) {
            if (regionName.equals(jobInfo.getRegionName()) && deployName.equals(jobInfo.getDeployName())
                    && groupName.equals(jobInfo.getGroupName()) && jobName.equals(jobInfo.getJobName())) {
                return jobInfo;
            }
        }
        return null;
    }

    /**
     * 解析所有
     */
    public void parse() {
        List<String> regionNames = HomePath.getRegionNames();
        regionNames.forEach(this::parseRegion);
    }

    /**
     * 按照域解析
     *
     * @param regionName
     */
    public void parseRegion(String regionName) {
        List<String> deployNames = HomePath.getDeployNames(regionName);
        for (String deployName : deployNames) {
            parseDeploy(regionName, deployName);
        }
        // 移除已经消失的deployName
        removeExclude(deployNames, regionName);
    }

    /**
     * 移除失效的
     *
     * @param deployNames
     */
    private void removeExclude(List<String> deployNames, String regionName) {
        Iterator<Entry<String, JobInfo>> it = jobInfos.entrySet().iterator();
        while (it.hasNext()) {
            JobInfo jobInfo = it.next().getValue();
            if (!deployNames.contains(jobInfo.getDeployName()) && jobInfo.getRegionName().equals(regionName)) {
                it.remove();
            }
        }
    }

    /**
     * 解析安装包下的
     *
     * @param regionName
     * @param deployName
     */
    public void parseDeploy(String regionName, String deployName) {
        ParamMap infoProps = WorkerConfParse.parseInfo(regionName, deployName);
        Long version = null;
        if (infoProps != null) {
            version = infoProps.getLong("version");
        }
        File deployPath = DeployPathUtils.getDeployPath(regionName, deployName, version);
        if (deployPath == null) {
            logger.warn("can not find worker deploy path for:" + regionName + "," + deployName + "," + version);
            return;
        }
        String jobXmlPath = HomePath.getJobXmlPath(deployPath.getPath());
        try {
            XmlConfig config = new XmlConfig();
            config.loadConfig(jobXmlPath);
            List<ParamMap> groups = config.getParamMapsByPath("jwater/jobGroup");
            if (groups == null) {
                return;
            }
            parseGroup(regionName, deployName, infoProps, groups);
        } catch (Exception e) {
            logger.error("parse error for:" + jobXmlPath, e);
        }
    }

    /**
     * 按照组解析
     *
     * @param regionName
     * @param deployName
     * @param infoProps
     * @param groups
     */
    private void parseGroup(String regionName, String deployName, ParamMap infoProps, List<ParamMap> groups) {
        // 标记删除
        List<JobInfo> removeJobs = getDeployJobInfo(regionName, deployName);
        Set<String> removeKeys = new HashSet<>();
        for (JobInfo removeJob : removeJobs) {
            String jobKey = DataKeys.getJobKey(regionName, deployName, removeJob.getGroupName(),
                    removeJob.getJobName());
            removeKeys.add(jobKey);
        }
        // 解析
        for (ParamMap group : groups) {
            String groupName = group.getString("groupName");
            String cron = group.getString("cron");
            String groupDesc = group.getString("desc");
            List<ParamMap> jobs = group.getParamMaps("job");
            int sn = 0;
            for (ParamMap job : jobs) {
                sn++;
                String jobName = job.getString("jobName");
                String className = job.getString("class");
                String jobDesc = job.getString("desc");
                ParamMap props = parseJobProps(job);
                JobInfo jobInfo = new JobInfo();
                jobInfo.setSn(sn);
                jobInfo.setRegionName(regionName);
                jobInfo.setDeployName(deployName);
                jobInfo.setGroupName(groupName);
                jobInfo.setCron(cron);
                jobInfo.setJobName(jobName);
                jobInfo.setClassName(className);
                jobInfo.setGroupDesc(groupDesc);
                jobInfo.setJobDesc(jobDesc);
                jobInfo.setInfoProps(infoProps);
                jobInfo.setProps(props);
                String jobKey = DataKeys.getJobKey(regionName, deployName, groupName, jobName);
                jobInfos.put(jobKey, jobInfo);
                removeKeys.remove(jobKey);
            }
        }
        // 删除
        removeKeys.forEach((key) -> {
            jobInfos.remove(key);
        });
    }

    /**
     * 解析属性
     *
     * @param job
     * @return
     */
    private static ParamMap parseJobProps(ParamMap job) {
        Map<String, Object> map = new HashMap<>();
        List<ParamMap> props = job.getParamMaps("prop");
        for (ParamMap prop : props) {
            map.put(prop.getString("key"), prop.getString("value"));
        }
        return ParamMapImpl.wrap(map);
    }
}
